<?php

/**
 * Class for Controller Exceptions Managing 
 * @author Francesco
 *
 */
class ControllerException extends Exception {

	const missing_controller_method = 10;
	const controller_generic_error = 20;
	const controller_no_exception = 40;
}

/**
 * Controller Abstarct class
 * @author Francesco
 *
 */
abstract class Controller {
	
	/**
	 * System global variable with all the infos you need
	 * @var System
	 */
	protected $system;
	
	/**
	 * Data coming from model
	 * @var unknown
	 */
	protected $data;
	
	/**
	 * Request params
	 * @var unknown
	 */
	protected $request;
	
	/**
	 * Observers caricati del model
	 * @var unknown_type
	 */
	public $observers = array();
	
	/**
	 * Constructor, initialize the Viola controller logic
	 * @param System $system
	 */
	function __construct(System $system){
		try{
			$this->system = &$system;
			$this->data = $this->system->model->data;
			$this->observers = $this->system->controller_observers;
			//If Mvc action exists execute the omonymous mehtod elsewhere, init!!
			if(MVC::FunctionExists($this->system->mvc_action['action'], $this)){
				$ob = get_class($this);
				call_user_func_array(array($ob, $this->system->mvc_action['action']), array() );
			} else {
				$this->init();
			}
			$this->request = $this->system->request;
		}catch (ControllerException $e){
			//Manage possible exception
			$system->__system_message = new ExceptionHandler($e);
		}
		
	}
	
	/**
	 * Abstract public amazing function.... init!!
	 */
	abstract public function init();
	
	/**
	 * Set variable for View side
	 * @param string $key
	 * @param string $val
	 */
	protected function set($key, $val){
		$this->system->view_vars[$key] = $val;
	}
	
	/**
	 * Set a system Event
	 * @see Model
	 * @param string $event
	 */
	protected function SetSystemEvent($event){
		$this->system->model->SetSystemEvent($event);
	}
	
	/**
	 * Create a persistent object, where you want!
	 * @param object $class
	 * @param string $type
	 * @param string $name
	 */
	protected function SetPersistentObject($class, $type = '_session_', $name){
		switch($type){
			case '_session_':
				$this->create_session_persistence($name, $class);
				break;
			case '_file_':
				$this->create_file_persistence($name, $class);
				break;
			case '_db_':
				$this->create_db_persistence($name, $class);
				break;
		}
		
	}
	
	/**
	 * Returns a preset persistent object
	 * @param string $type
	 * @param string $name
	 */
	protected function GetPersistentObject($type, $name){
		switch($type){
			case '_session_':
				$this->get_session_persistence($name);
				break;
			case '_file_':
				$this->get_file_persistence($name);
				break;
			case '_db_':
				$this->get_db_persistence($name);
				break;
		}
	}
	
	/**
	 * Create a persistent object using Session if is available
	 * @param string $name
	 * @param object $class
	 * @throws ControllerException
	 */
	private function create_session_persistence($name, $class){
		if(!isset($_SESSION))session_start();
		if(session_status() === PHP_SESSION_ACTIVE){
			$_SESSION[$name] = base64_encode(gzcompress(serialize($class),9));
			$this->system->persistent_object['_session_'][$name] = $class;
		} else {
			throw new ControllerException('session_unavailable', ControllerException::controller_generic_error);
		}
	}

	/**
	 * Create a file with persistent object inside
	 * @param unknown $name
	 * @param unknown $class
	 * @throws ControllerException
	 */
	private function create_file_persistence($name, $class){
		if(file_exists(TEMP_DIR.$name))throw new ControllerException('file_persistence_already_exists_be_carefull_dear_friend', ControllerException::controller_generic_error);
		$f = fopen(TEMP_DIR.$name,"w");
		if(fwrite($f,base64_encode(gzcompress(serialize($class),9)))){
			fclose($f);
			$this->system->persistent_object['_file_'][$name] = $class;
		}else {
			throw new ControllerException('writebale_file_unavailable', ControllerException::controller_generic_error);
		}
	}
	
	/**
	 * Create a persistent object in the db resource
	 * @param unknown $name
	 * @param unknown $class
	 */
	private function create_db_persistence($name, $class){
		$this->system->model->check_table_persistence();
		$obj = base64_encode(gzcompress(serialize($class),9));
		$pers_obj_id = $this->system->model->set_db_persistent_object($name, $obj);
		$this->system->persistent_object['_db_']['id'] = $pers_obj_id;
		$this->system->persistent_object['_db_'][$name] = $obj;
	}
	
	/**
	 * Return a persistent object stored in session
	 * @param string $name
	 * @throws ControllerException
	 */
	private function get_session_persistence($name){
		if(!isset($_SESSION))session_start();
		if(session_status() === PHP_SESSION_ACTIVE){
			if(isset($_SESSION[$name])){
				$this->system->persistent_object['_session_'][$name] = unserialize(gzuncompress(base64_decode($_SESSION[$name])));	
			} else {
				throw new ControllerException($name.'_is_not_persistent_object', ControllerException::controller_generic_error);
			}
		} else {
			throw new ControllerException('session_unavailable', ControllerException::controller_generic_error);
		}
	}
	
	/**
	 * Return a persistent object stored in a file
	 * @param string $name
	 */
	private function get_file_persistence($name){
		if(!file_exists(TEMP_DIR.$name)){
			$this->system->persistent_object['_file_'][$name] = unserialize(gzuncompress(base64_decode(file_get_contents(TEMP_DIR.$name))));
		} else {
			throw new ControllerException($name.'_is_not_persistent_object', ControllerException::controller_generic_error);
		}
	}
	
	/**
	 * Return a persistent object stored in db
	 * @param string $name
	 */
	private function get_db_persistence($name){
		$obj = $this->system->model->get_db_persistence($name);
	}
	
	/**
	 * Distruttotre, se ci sono observers li esegue prima di chiudere la classe.
	 */
	function __destruct(){
		if(!empty($this->observers)){
			$nr = count($this->observers);
			for($i = 0; $i < $nr; $i++){
				$this->observers[$i]->control($this);
			}
		}
	}
}